package net.mycrub.bitwise.core.impl;

import net.mycrub.bitwise.core.ILayer;
import net.mycrub.bitwise.core.IRetroActionCallback;

import org.simpleframework.xml.Root;

/**
 * The input of this layer is split in as many chunks as there are collaborating
 * layers. The output of all the layers are then concatenated as an output.
 */
@Root
public class SerialConcatLayer extends AbstractCollaborativeLayer {

    /**
     * Add a collaborating layer
     */
    public void addLayer(ILayer layer) {
        layers.add(layer);
    }

    /** {@inheritDoc} */
    public int getInputSize() {
        int size = 0;
        for (ILayer layer : layers) {
            size += layer.getInputSize();
        }
        return size;
    }

    /** {@inheritDoc} */
    public int getOutputSize() {
        int size = 0;
        for (ILayer layer : layers) {
            size += layer.getOutputSize();
        }
        return size;
    }

    /** {@inheritDoc} */
    public double[] collaborate(double[] input, IRetroActionCallback callback) {
        double[] output = new double[getOutputSize()];

        int readIput = 0;
        int writtenOutput = 0;
        for (ILayer layer : layers) {
            double[] subInput = new double[layer.getInputSize()];
            System.arraycopy(input, readIput, subInput, 0, subInput.length);

            double[] subOutput = layer.process(subInput, callback);
            System.arraycopy(subOutput, 0, output, writtenOutput,
                    subOutput.length);

            readIput += subInput.length;
            writtenOutput += subOutput.length;
        }

        return output;
    }

    @Override
    protected AbstractCollaborativeLayer getNewInstance() {
        return new SerialConcatLayer();
    }

}
